package com.xianggu.agency.cglibProxy;

import com.xianggu.agency.demo.impl.MyInterface2;

import java.lang.reflect.Method;

/**
 * @author chengjy
 * @date 2025/3/18
 */
public class CgLibProxyFunctionUtils {

    // 组装代理类的所有公有方法
    public static String joinMethod(Method method) {
        // 获取方法名
        String methodName = method.getName();
        // 获得参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        // 获得返回值
        Class<?> returnType = method.getReturnType();

        // 组装代理方法
        StringBuilder args = new StringBuilder();
        // 拼接方法传参的字符串形式
        args.append("new Class[]{");

        StringBuilder func = new StringBuilder("    @Override\n" + "    public " + returnType.getSimpleName() + " " + methodName + "(");
        for (int i = 0; i < parameterTypes.length; i++) {
            // 书写方法头参数列表
            func.append(parameterTypes[i].getName()).append(" arg").append(i);
            // 书写方法体内反射回去当前方法的参数列表
            args.append(parameterTypes[i].getName()).append(".class ");
            if (i < parameterTypes.length - 1) {
                func.append(", ");
                args.append(", ");
            }else {
                func.append(") {\n");
            }
        }
        // 判断返回值类型
        String methodBody = "";
        if ("void".equals(returnType.getSimpleName())){
            methodBody = "        this.handler.invoke(this , proxyMethod, args);\n";
        }else {
            methodBody = "        return ("+returnType.getSimpleName()+")this.handler.invoke(this , proxyMethod, args);\n";
        }
        // 拼接全部方法
        args.append("}\n");
        func.append("       Method proxyMethod = null;\n" +
                "        try {\n" +
                "            proxyMethod = this.getClass().getMethod(\""+methodName+"\", "+ args +
                "            );\n" +
                "        } catch (NoSuchMethodException e) {\n" +
                "            throw new RuntimeException(e);\n" +
                "        }"+
                "        int paramSize = proxyMethod.getParameterTypes().length;\n" +
                "        Object[] args = new Object[paramSize];\n" +
                "        for (int i = 0; i < paramSize; i++) {\n" +
                "            args[i] = \"arg\" + i;\n" +
                "        }\n" +
                        methodBody);
        func.append("    }\n");
        return func.toString();
    }

    public static void main(String[] args) {
        Class<MyInterface2> myInterface2Class = MyInterface2.class;
        Method[] methods = myInterface2Class.getMethods();
        for (Method method : methods) {
            System.out.println(joinMethod(method));
        }

        try {
            Method method = myInterface2Class.getMethod("func1", new Class[]{String.class, String.class});
            System.out.println(method);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
